package com.lxxin.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lxxin.dao.BlogDao;
import com.lxxin.dao.CarouselDao;
import com.lxxin.exception.NotFoundException;
import com.lxxin.pojo.*;
import com.lxxin.pojo.queryvo.BlogManageQueryVo;
import com.lxxin.service.BlogService;
import com.lxxin.utils.AnchorUtils;
import com.lxxin.utils.MarkDown2HtmlUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

@Service
public class BlogServiceImpl implements BlogService {
    @Autowired
    private BlogDao blogDao;

    @Autowired
    private CarouselDao carouselDao;

    @Override
    public Blog findBlogById(Long id) {
        Blog blogById = blogDao.findBlogById(id);
        blogById.getType();
        List<Tag> tagList = blogById.getTagList();
        List<Long> tagIds = new ArrayList<>();
        if (tagList.size() > 0) {
            for (Tag tag : tagList) {
                tagIds.add(tag.getId());
            }
        }
        blogById.setTagIds(tagIds);
        return blogById;
    }

    @Override
    public Blog findAndConvertBlogById(Long id) {
        Blog blogById = blogDao.findBlogById(id);
        if (blogById == null) {
            throw new NotFoundException("博客不存在");
        }
        String content = blogById.getContent();
        //将Markdown语句转为Html
        String parseContent = MarkDown2HtmlUtils.markdown2Html(content);
        //为标题设置锚点
        parseContent = AnchorUtils.addAnchor(parseContent);
        blogById.setContent(parseContent);
        blogById.getType();
        blogById.getUser();
        blogById.getTagList();
        return blogById;
    }

    @Override
    public PageInfo<Blog> findBlogList(Integer currentPage, Integer pageSize, BlogManageQueryVo blogManageQueryVo) {
        PageHelper.startPage(currentPage, pageSize, "update_time desc");
        List<Blog> blogList = blogDao.findBlogList(blogManageQueryVo);
        blogList.forEach(item -> item.getType());
        return new PageInfo<Blog>(blogList);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public PageInfo<Blog> findHomeBlogList(Integer currentPage, Integer pageSize) {
        PageHelper.startPage(currentPage, pageSize, "is_top=1 desc, create_time desc");
        List<Blog> blogList = blogDao.findHomeBlogList();
        PageInfo<Blog> blogPageInfo = new PageInfo<>(blogList);
        blogList.forEach(item -> {
            item.getType();
            item.getUser();
            item.getTagList();
        });
        blogPageInfo.setList(blogList);
        return blogPageInfo;
    }

    @Override
    public List<Archives> findArchivesBlogList() {
        List<Blog> archivesBlogList = blogDao.findArchivesBlogList();
        archivesBlogList.forEach(item -> {
            item.getType();
            item.getUser();
            item.getTagList();
        });
        Map<String, List<Blog>> archivesMap = getArchivesMap(archivesBlogList);
        List<Archives> archivesList = new ArrayList<>();
        for (Map.Entry<String, List<Blog>> entry : archivesMap.entrySet()) {
            Archives archives = new Archives();
            archives.setYear(entry.getKey());
            archives.setBlogList(entry.getValue());
            archivesList.add(archives);
        }
        Collections.sort(archivesList);
        return archivesList;
    }

    /**
     * 转换归档博客列表格式
     *
     * @param blogList
     * @return
     */
    private Map<String, List<Blog>> getArchivesMap(List<Blog> blogList) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        Map<String, List<Blog>> archivesMap = blogList.stream()
                .collect(groupingBy(b -> sdf.format(b.getCreateTime())));
        return archivesMap;
    }

    @Override
    public List<Blog> findTopRecommendBlogList(Integer top) {
        return blogDao.findTopRecommendBlogList(top);
    }

    @Override
    public PageInfo<Blog> findSearchBlog(Integer currentPage, Integer pageSize, String search) {
        PageHelper.startPage(currentPage, pageSize);
        List<Blog> searchBlog = blogDao.findSearchBlog(search);
        searchBlog.forEach(item -> {
            item.getType();
            item.getUser();
            item.getTagList();
        });
        return new PageInfo<Blog>(searchBlog);
    }

    @Override
    public PageInfo<Blog> findBlogByTagId(Integer currentPage, Integer pageSize, Long tagId) {
        PageHelper.startPage(currentPage, pageSize, "create_time desc");
        List<Blog> blogByTagId = blogDao.findBlogByTagId(tagId);
        blogByTagId.forEach(item -> {
            item.getType();
            item.getUser();
            item.getTagList();
        });
        return new PageInfo<Blog>(blogByTagId);
    }

    @Override
    public PageInfo<Blog> findBlogByTypeId(Integer currentPage, Integer pageSize, Long typeId) {
        PageHelper.startPage(currentPage, pageSize, "create_time desc");
        List<Blog> blogByTypeId = blogDao.findBlogByTypeId(typeId);
        blogByTypeId.forEach(item -> {
            item.getType();
            item.getUser();
            item.getTagList();
        });
        return new PageInfo<Blog>(blogByTypeId);
    }

    @Override
    public Long updateComments(Long id, Long comments) {
        return blogDao.updateComments(id, comments);
    }

    @Override
    public Count findCount() {
        Count count = new Count();
        List<Integer> list = blogDao.findAllCount();
        count.setBlogCount(list.get(0));
        count.setTypeCount(list.get(1));
        count.setTagCount(list.get(2));
        return count;
    }

    @Override
    public Long findWordCount(Long id) {
        String content = blogDao.findContent(id);
        Integer result = wordCount(content);
        return result.longValue();
    }

    @Override
    public Long findViewsById(Long id, Boolean isAdd) {
        Long views = blogDao.findViews(id);
        if(isAdd){
            //更新阅读次数
            blogDao.updateViews(id);
        }
        return views;
    }

    @Override
    public List<Long> findViewsByIds(List<Long> ids) {
        List<Long> viewsList = blogDao.findViewsList(ids);
        return viewsList;
    }

    @Override
    public Long findAllWordCount() {
        List<String> contents = blogDao.findContents();
        String allContents = "";
        for (String content : contents) {
            allContents += content;
        }
        Integer result = wordCount(allContents);
        return result.longValue();
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public int saveBlog(Blog blog) {
        blog.setCreateTime(System.currentTimeMillis());
        blog.setUpdateTime(System.currentTimeMillis());
        blog.setState(true);
        int record = blogDao.saveBlog(blog);
        if (blog.getTagList().size() > 0) {
            blogDao.saveBlogTag(blog);
        }
        return record;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public int updateBlog(Blog blog) {
        Blog blogById = findBlogById(blog.getId());
        if (blogById != null) {
            blog.setUpdateTime(System.currentTimeMillis());
            int record = blogDao.updateBlog(blog);
            blogDao.deleteBlogTag(blog);
            if (blog.getTagList().size() > 0) {
                blogDao.saveBlogTag(blog);
            }
            return record;
        }
        return 0;
    }

    @Override
    public void deleteBlog(Long id) {
        blogDao.deleteBlog(id);
    }

    @Override
    public List<Carousel> findCarouselList() {
        return carouselDao.findCarouselList();
    }

    @Override
    public Carousel findCarouselById(Long id) {
        return carouselDao.findCarouselById(id);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public int saveCarousel(Carousel carousel) {
       return carouselDao.saveCarousel(carousel);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public int updateCarousel(Carousel carousel) {
        Carousel carouselById = carouselDao.findCarouselById(carousel.getId());
        if (carouselById != null) {
            return carouselDao.updateCarousel(carousel);
        }
        return 0;
    }

    @Override
    public void deleteCarousel(Long id) {
        carouselDao.deleteCarousel(id);
    }

    /**
     * 统计中文字数
     * @param string
     * @return
     */
    private int wordCount(String string) {
        if (string == null) {
            return 0;
        }
        String englishString = string.replaceAll("[\u4e00-\u9fa5]", "");
        String[] englishWords = englishString.split("[\\p{P}\\p{S}\\p{Z}\\s]+");
        int chineseWordCount = string.length() - englishString.length();
        int otherWordCount = englishWords.length;
        if (englishWords.length > 0 && englishWords[0].length() < 1) {
            otherWordCount--;
        }
        if (englishWords.length > 1 && englishWords[englishWords.length - 1].length() < 1) {
            otherWordCount--;
        }
        return chineseWordCount + otherWordCount;
    }
}
